using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data;
using Jandaya.Framework;
using FirebirdSql.Data.FirebirdClient;

namespace Jandaya.Framework.DAO
{
	
	/// <summary>
	/// Responsável por criar e inicializar os objetos de conexão.
	/// </summary>
	public class ConnectionManager: IFactory<FbConnection>, IDisposable
	{
		private const int POOL_SIZE = 5;
		
		private const string DEFAULT_CONN_STRING = "Database={0};User ID={1};Password={2};Charset=ISO8859_1";
		private IList<FbConnection> Connections = new List<FbConnection>(POOL_SIZE);
		
	
		public ConnectionManager(){}
		
		public ConnectionManager(string pDatabase, string pUser, string pPassword)
		{		
			Database = pDatabase;
			User = pUser;
			Password = pPassword;			
			CreateNewConnection();	
		}
			
		
		#region 'IDisposable'
		public void Dispose(){
			if(Connections!= null){
				foreach (FbConnection cnn in Connections){
					cnn.Close();				
				}
				Connections.Clear();
				Connections = null;
			}
		}
		#endregion
		
		public string Database{ get; set; }
		public string User{ get; set; }
		public string Password{ get; set; }
		
		
		public bool TestConnection(string pHost, string pDatabase, string pUser, string pSenha, out string pLog){					
			string cnnstring = string.Format(DEFAULT_CONN_STRING, pHost + ":" + pDatabase, pUser, pSenha);
			pLog = "Iniciando a conexão...\n";
			try{
				FbConnection cnn = new FbConnection(cnnstring);			
				pLog += "Abrindo a conexão...";
				cnn.Open();
				if (cnn.State == ConnectionState.Open){
					pLog += "ok";
					cnn.Close();					
				}
			}
			catch (FbException fbex){
				pLog += string.Format("\nException:\n{0}", fbex.Message);
				return false;
			}
			return true;
		}	
	
		
		private string GetConnectionString(){
			if (
			    	(string.IsNullOrEmpty(Database)) ||
					(string.IsNullOrEmpty(User)) ||
					(string.IsNullOrEmpty(Password))
			    )
			    return string.Empty;		
			return string.Format(DEFAULT_CONN_STRING, Database, User, Password);
		}		
		
		
		private void CreateNewConnection(){
			FbConnection conn = new FbConnection();			
			conn.ConnectionString = GetConnectionString();
			Connections.Add(conn);
			return;
		}
		
		
		#region 'IFactory'
		public FbConnection GetNewInstance(){
			return GetConnection();
		}
		#endregion
		

		/// <summary>
		/// Recupera uma conexão do pool criando uma nova se for necessário.
		/// </summary>
		/// <returns>
		/// A <see cref="DAOConnection"/>
		/// </returns>
		public FbConnection GetConnection(){
			if (Connections.Count == 0)
				CreateNewConnection();
			for(int i=0; i < Connections.Count; i++){
				switch(Connections[i].State){
					
				case ConnectionState.Broken:
				case ConnectionState.Closed:
					Debug.WriteLine(string.Format("Tentando abrir a conexão {0} em {1}", i, Connections[i].ConnectionString));
					Connections[i].Open();
					Debug.WriteLine(string.Format("Conexão {0} aberta!", i));					
					return Connections[i];					
					
				case ConnectionState.Connecting:
				case ConnectionState.Executing:
				case ConnectionState.Fetching:
					if ((i == Connections.Count-1) && (Connections.Count < POOL_SIZE)){
					   CreateNewConnection();	
					   return Connections[i+1];	
					}					
					break;
				case ConnectionState.Open:
					return Connections[i];					
				}
			}
			throw new OverflowException("O número máximo de conexões no pool foi atingido!");
		}
	}
}

